package com.shiro.demo.shiro;

import com.shiro.demo.domain.Permission;
import com.shiro.demo.domain.Role;
import com.shiro.demo.domain.User;
import com.shiro.demo.service.UserRolePermissionService;
import com.shiro.demo.service.UserService;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import javax.annotation.PostConstruct;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

/**
 * @author tracyclock 2017-12-08
 * 用于进行权限信息的验证，需要我们自己实现
 */
public class MyShiroRealm extends AuthorizingRealm {

    private Logger logger = LoggerFactory.getLogger(this.getClass());
    @Autowired
    private UserService userService;
    @Autowired
    private UserRolePermissionService userRolePermissionService;

    /**
     * AuthorizationInfo 是授权访问控制，用于对用户进行的操作授权，证明该用户是否允许进行当前操作，如访问某个链接，某个资源文件等。
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        logger.info("用户授权-->MyShiroRealm  doGetAuthorizationInfo()  start~");
        SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
        User user  = (User)principalCollection.getPrimaryPrincipal();

        //用户role集合
        List<Role> roleList = userRolePermissionService.roleListByUserId(user.getId());
        if(roleList == null || roleList.size() <= 0){
            return authorizationInfo;
        }
        Set<Long> roleIds = new HashSet<>();
        Set<String> roleSet = new HashSet<>();
        Set<String> permissionSet = new HashSet<>();
        for(Role role : roleList){
            roleSet.add(role.getType());
            roleIds.add(role.getId());
        }
        logger.info("MyShiroRealm  doGetAuthorizationInfo()  roleSet{}",roleSet);

        //用户permission集合
        List<Permission> permissionList = this.userRolePermissionService.permissionListByRoleIds(roleIds);
        if(permissionList != null && permissionList.size() > 0){
            for (Permission permission :permissionList) {
                permissionSet.add(permission.getName());
            }
        }
        logger.info("MyShiroRealm  doGetAuthorizationInfo()  permissionSet{}",permissionSet);

        //将用户的角色信息，权限信息，添加到authorizationInfo
        //debug可以看到，返回authorizationInfo后，就开始验证权限是否符合，未授权就会跳转之前配置的未授权页面
        authorizationInfo.setRoles(roleSet);
        authorizationInfo.setStringPermissions(permissionSet);

        return authorizationInfo;
    }

    /**
     * AuthenticationInfo 是用来验证用户身份,判断登陆是否成功
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        logger.info("用户验证----->MyShiroRealm   doGetAuthenticationInfo() start~");
        //从token获取用户的输入的账号
        UsernamePasswordToken token = (UsernamePasswordToken)authenticationToken;
        String name = token.getUsername();//得到用戶名
        //通过name从数据库中查找 User对象
        User user = userService.getUserByName(name);

        //此处可用缓存机制实现N点登陆，几次登陆失败后禁止登陆等操作
        if(user == null){
            throw new AccountException("帐号不正确！");
        }else if(user.getStatus().intValue() == 0){
            throw new DisabledAccountException("此帐号已经设置为禁止登录！");
        }
        logger.info("doGetAuthenticationInfo() user{}",user);
        SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(user,user.getPassword(), ByteSource.Util.bytes(user.getSalt()),getName());
        return authenticationInfo;
    }


    /**
     * 重写shiro的密码验证方式
     * CustomCredentialsMatcher 自己实现的加盐验证
     */
    @PostConstruct
    public void initCredentialsMatcher() {
        setCredentialsMatcher(new CustomCredentialsMatcher());
    }

}
